import React from "react";
import ReactDOM from "react-dom/client";

class Hello extends React.Component {
  componentDidMount() {
    console.log("Hello - componentDidMount");
  }

  componentDidUpdate() {
    console.log("Hello - componentDidUpdate");
  }

  /**
   * 卸载阶段，组件即将卸载之前触发  - beforeDestroy
   *    1. 清理和收尾的工作
   *    2. removeEventelister
   *    3. clearTimeout clearInterval
   */
  componentWillUnmount() {
    console.log("Hello - componentWillUnmount");
  }

  render() {
    console.log("Hello - render");
    return (
      <div>
        <h1>Hello, {this.props.name}</h1>
      </div>
    );
  }
}

class App extends React.Component {
  state = {
    person: {
      name: "张三",
      age: 18,
    },

    isShowHello: true, // 是否显示Hello组件
  };

  /**
   * 挂载完成，真实DOM更新完成   = mounted
   *    1. ajax 做请求
   *    2. 全局 事件的监听  window.addEven('')
   *    3. setTimeout setInterval
   *    4. 挂载阶段 - 获取到真实的DOM对象
   */
  componentDidMount() {
    console.log("App - componentDidMount");
  }

  /**
   * 更新阶段，真实DOM元素已完成更新时 执行   - updated
   *    1. 一般不用操作它
   *    2. 可以在这个函数中 setState 但是需要做好条件的判断。
   *        原因是：componentDidUpdate 函数会触发多次，会造成递归调用，导致内存溢出。
   *        姓名真实的修改之后，让年龄修改为20
   *    3. 接收三个参数
   *        1. prevProps  - 更新之前的 props 数据
   *        2. prevState  - 更新之前的 state 数据
   *        3. snapshot   - 默认是个 undefined 。后续补充
   */
  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log("App - componentDidUpdate");

    console.log("App - prevProps", prevProps);
    console.log("App - prevState", prevState);
    console.log("App - snapshot", snapshot);

    // console.log(this.refs.pRef.innerHTML);

    if (this.state.person.name !== prevState.person.name) {
      this.setState({
        person: {
          ...this.state.person,
          age: 20,
        },
      });
    }
  }

  render() {
    console.log("App - render");
    return (
      <div>
        <h1 ref="h1Ref">App</h1>
        <p ref="pRef">姓名：{this.state.person.name}</p>
        <p>年龄：{this.state.person.age}</p>
        <button
          onClick={() => {
            this.state.person.age = 20;
          }}
        >
          修改年龄为 20
        </button>
        <button
          onClick={() => {
            // 一、使用 setState()
            this.setState({
              person: {
                ...this.state.person,
                name: "李四",
              },
            });
            // 二、使用 forceUpdate() 强制更新（重新触发 render 函数）
            //    此方式，不推荐使用。因为会导致我们看代码看效果时非常的诧异。
            //            会导致一些其他钩子函数中 prevState 参数异常
            // this.state.person.name = "李四";
            // this.forceUpdate();
          }}
        >
          修改姓名为李四
        </button>
        <button
          onClick={() => {
            this.setState({
              isShowHello: !this.state.isShowHello,
            });
          }}
        >
          切换 isShowHello
        </button>

        {this.state.isShowHello && <Hello name={this.state.person.name} />}

        {/* 
          下面代码请注意，会将 person 中 age 给丢失？
          setState 的操作是一个浅合并
        */}
        {/* <button
          onClick={() => {
            this.setState({
              person: {
                name: "李四",
              },
            });
          }}
        >
          修改姓名为李四
        </button> */}
      </div>
    );
  }
}

const root = ReactDOM.createRoot(document.querySelector("#root"));
root.render(<App />);
